package com.ssy.lingxi.search.serviceImpl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.constant.tree.Node;
import com.ssy.lingxi.common.constant.tree.TreeUtils;
import com.ssy.lingxi.common.model.vo.PageVO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.component.redis.service.IRedisStringUtils;
import com.ssy.lingxi.search.api.model.request.CommoditySearchRequest;
import com.ssy.lingxi.search.api.model.request.StoreIdListRequest;
import com.ssy.lingxi.search.api.model.response.BrandResponse;
import com.ssy.lingxi.search.api.model.response.CategoryResponse;
import com.ssy.lingxi.search.api.model.response.CommoditySearchResponse;
import com.ssy.lingxi.search.common.SortTypeEnum;
import com.ssy.lingxi.search.common.tree.CategoryNode;
import com.ssy.lingxi.search.common.utils.ListPageUtil;
import com.ssy.lingxi.search.entity.Commodity;
import com.ssy.lingxi.search.repository.CommodityRepository;
import com.ssy.lingxi.search.service.ICommodityService;
import com.ssy.lingxi.search.service.ITemplateService;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 商品实现类
 * @author jw.chen
 * @version 2.0.0
 * @date 2020/6/22
 */
@Service
public class TemplateServiceImpl implements ITemplateService {

    @Resource
    private CommodityRepository commodityRepository;

    @Resource
    private ICommodityService commodityService;

    @Resource
    private RestHighLevelClient restHighLevelClient;

    @Resource
    private IRedisStringUtils redisStringUtils;

    /**
     * 查询商品分类树
     * @param shopId            商城id
     * @param memberId          会员id
     * @param memberRoleId      会员角色id
     */
    @Override
    public List<Node> getCategoryTree(Long shopId, Long memberId, Long memberRoleId) {
        // 查询条件
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        //定义参数变量
        String esField;
        String redisKey;
        if(memberId != null && memberId > 0){
            esField = "customerCategory.fullId.keyword";
            redisKey = Constants.REDIS_KEY_CUSTOMER_CATEGORY;

            // 拼接会员id搜索
            queryBuilder.must(QueryBuilders.matchQuery("memberId", memberId));
            queryBuilder.must(QueryBuilders.matchQuery("memberRoleId", memberRoleId));
        }else{
            esField = "customerCategory.category.fullId.keyword";
            redisKey = Constants.REDIS_KEY_CATEGORY;
        }

        // 按商城环境
        if(shopId != null && shopId > 0){
            queryBuilder.must(QueryBuilders.matchQuery("commodityShopList.shopId", shopId));
        }

        //构建查询条件
        SearchRequest search = new SearchRequest(Constants.ES_COMMODITY_INDEX);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(0);
        searchSourceBuilder.query(queryBuilder);
        //分组
        TermsAggregationBuilder aggregationCategoryId = AggregationBuilders.terms("group_categoryId").field(esField).size(1200000);
        searchSourceBuilder.aggregation(aggregationCategoryId);
        search.source(searchSourceBuilder);
        try{
            CategoryNode categoryNode = new CategoryNode();
            //搜索
            SearchResponse searchResponse = restHighLevelClient.search(search, RequestOptions.DEFAULT);
            Aggregations aggregations = searchResponse.getAggregations();
            if(aggregations != null){
                Terms brandTerms = aggregations.get("group_categoryId");
                List<? extends Terms.Bucket> brandBuckets = brandTerms.getBuckets();
                if(brandBuckets != null){
                    brandBuckets.forEach(bucket -> {
                        //将品类进行组装
                        String fullId = String.valueOf(bucket.getKey());
                        if(fullId.contains(Constants.SPLIT_STR_FULL_ID)){
                            String[] split = fullId.split(Constants.TRANSFER_STR + Constants.SPLIT_STR_FULL_ID);
                            if(split.length > 0){
                                for(int i = 0; i < split.length; i++){
                                    if(i == 0){
                                        //一级品类
                                        Set<Long> rootList = categoryNode.getRootList() == null ? new HashSet<>() : categoryNode.getRootList();
                                        rootList.add(Long.valueOf(split[i]));
                                        categoryNode.setRootList(rootList);
                                    }
                                    //所有品类
                                    Set<Long> sourceList = categoryNode.getSourceList() == null ? new HashSet<>() : categoryNode.getSourceList();
                                    sourceList.add(Long.valueOf(split[i]));
                                    categoryNode.setSourceList(sourceList);
                                }
                            }
                        }else{
                            //商品挂在一级品类下
                            Set<Long> rootList = categoryNode.getRootList() == null ? new HashSet<>() : categoryNode.getRootList();
                            rootList.add(Long.valueOf(fullId));
                            categoryNode.setRootList(rootList);
                            //所有品类
                            Set<Long> sourceList = categoryNode.getSourceList() == null ? new HashSet<>() : categoryNode.getSourceList();
                            sourceList.add(Long.valueOf(fullId));
                            categoryNode.setSourceList(sourceList);
                        }
                    });
                }
            }
            Map<String, String> categoryMap = redisStringUtils.hGetAll(redisKey, Constants.REDIS_PRODUCT_INDEX);
            Set<Long> rootCategoryIdList = categoryNode.getRootList();
            Set<Long> sourceCategoryIdList = categoryNode.getSourceList();
            //组装树结构
            if(rootCategoryIdList != null && !rootCategoryIdList.isEmpty()){
                List<Node> rootList = TreeUtils.getNodeList(rootCategoryIdList, categoryMap);
                List<Node> sourceList = TreeUtils.getNodeList(sourceCategoryIdList, categoryMap);
                return TreeUtils.buildTree(sourceList, rootList);
            }
            return null;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 查询品牌列表
     * @param pageVO            分页对象
     * @param searchRequest     查询条件
     */
    @Override
    public PageData<BrandResponse> searchBrandList(PageVO pageVO, CommoditySearchRequest searchRequest){
        List<BrandResponse> brandList = new ArrayList<>();
        // 查询条件
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        // 获取查询参数
        Long memberId = searchRequest.getMemberId();
        Long memberRoleId = searchRequest.getMemberRoleId();
        String name = searchRequest.getName();
        Long categoryId = searchRequest.getCategoryId();
        Long customerCategoryId = searchRequest.getCustomerCategoryId();
        List<Long> idInList = searchRequest.getIdInList();
        List<Long> idNotInList = searchRequest.getIdNotInList();
        Long shopId = searchRequest.getShopId();

        // id搜索
        if(idInList != null && !idInList.isEmpty()){
            queryBuilder.must(QueryBuilders.termsQuery("brand.id", idInList));
        }
        if(idNotInList != null && !idNotInList.isEmpty()){
            queryBuilder.mustNot(QueryBuilders.termsQuery("brand.id", idNotInList));
        }

        // 拼接会员搜索
        if(memberId != null && memberId > 0){
            queryBuilder.must(QueryBuilders.matchQuery("memberId", memberId));
        }

        // 拼接会员搜索
        if(memberRoleId != null && memberRoleId > 0){
            queryBuilder.must(QueryBuilders.matchQuery("memberRoleId", memberRoleId));
        }

        // 拼接关键字搜索(品牌名称)
        if(StringUtils.isNotEmpty(name)){
            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(searchRequest.getName(), "brand.name");
            queryBuilder.must(multiMatchQueryBuilder);
        }

        // 拼接分类搜索
        String categoryKey;
        if(customerCategoryId != null && customerCategoryId > 0){
            categoryKey = "customerCategory.fullId:*";
            queryBuilder.must(QueryBuilders.queryStringQuery(categoryKey + String.format(Constants.CATEGORY_FULL_ID_NUM, customerCategoryId) + "*"));
        }
        if(categoryId != null && categoryId > 0){
            categoryKey = "customerCategory.category.fullId:*";
            queryBuilder.must(QueryBuilders.queryStringQuery(categoryKey + String.format(Constants.CATEGORY_FULL_ID_NUM, categoryId) + "*"));
        }

        // 按商城环境
        if(shopId != null && shopId > 0){
            queryBuilder.must(QueryBuilders.matchQuery("commodityShopList.shopId", shopId));
        }

        //构建查询条件
        SearchRequest search = new SearchRequest(Constants.ES_COMMODITY_INDEX);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(0);
        searchSourceBuilder.query(queryBuilder);
        //分组
        TermsAggregationBuilder aggregationBrandId = AggregationBuilders.terms("group_brandId").field("brand.id").size(1200000)
                .subAggregation(AggregationBuilders.terms("group_brandName").field("brand.name.keyword").subAggregation(AggregationBuilders.terms("group_brandLogoUrl").field("brand.logoUrl.keyword")));
        searchSourceBuilder.aggregation(aggregationBrandId);
        search.source(searchSourceBuilder);
        //搜索
        try{
            SearchResponse searchResponse = restHighLevelClient.search(search, RequestOptions.DEFAULT);
            Aggregations aggregations = searchResponse.getAggregations();
            if(aggregations != null){
                Terms brandTerms = aggregations.get("group_brandId");
                List<? extends Terms.Bucket> brandBuckets = brandTerms.getBuckets();
                if(brandBuckets != null){
                    brandBuckets.forEach(bucket -> {
                        Terms brandNameTerms = bucket.getAggregations().get("group_brandName");
                        List<? extends Terms.Bucket> brandNameBuckets = brandNameTerms.getBuckets();
                        if(brandNameBuckets != null){
                            brandNameBuckets.forEach(bucketName -> {
                                Terms brandLogoUrlTerms = bucketName.getAggregations().get("group_brandLogoUrl");
                                List<? extends Terms.Bucket> brandLogoUrlBuckets = brandLogoUrlTerms.getBuckets();
                                brandLogoUrlBuckets.forEach(bucketLogoUrl -> {
                                    BrandResponse brand = new BrandResponse();
                                    brand.setId(Long.valueOf(String.valueOf(bucket.getKey())));
                                    brand.setName(String.valueOf(bucketName.getKey()));
                                    brand.setLogoUrl(String.valueOf(bucketLogoUrl.getKey()));
                                    brandList.add(brand);
                                });
                            });
                        }
                    });
                }
            }
            // 分页
            PageData<BrandResponse> pageData = new PageData<>();
            pageData.setTotalCount((long) brandList.size());
            pageData.setData(ListPageUtil.page(brandList, pageVO.getCurrent(), pageVO.getPageSize()));

            //根据idInList进来的需要排序
            if(idInList != null && idInList.size() > 0 && CollectionUtil.isNotEmpty(pageData.getData())) {
                pageData.setData(
                        pageData.getData().stream().sorted(Comparator.comparingInt(a -> idInList.indexOf(a.getId()))).collect(Collectors.toList())
                );

            }

            return pageData;
        }catch (Exception e){
            return null;
        }
    }

    /**
     * 查询一级分类
     * @param shopId            商城id
     * @param memberId          会员id
     * @param memberRoleId      会员角色id
     */
    @Override
    public List<CategoryResponse> getFirstCategoryList(Long shopId, Long memberId, Long memberRoleId) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        //定义参数变量
        String esField;
        String redisKey;
        // 会员
        if(memberId != null && memberId > 0){
            queryBuilder.must(QueryBuilders.matchQuery("memberId", memberId));
            queryBuilder.must(QueryBuilders.matchQuery("memberRoleId", memberRoleId));
            esField = "customerCategory.fullId.keyword";
            redisKey = Constants.REDIS_KEY_CUSTOMER_CATEGORY;
        }else{
            esField = "customerCategory.category.fullId.keyword";
            redisKey = Constants.REDIS_KEY_CATEGORY;
        }

        // 按商城环境
        if(shopId != null && shopId > 0){
            queryBuilder.must(QueryBuilders.matchQuery("commodityShopList.shopId", shopId));
        }

        //构建查询条件
        SearchRequest search = new SearchRequest(Constants.ES_COMMODITY_INDEX);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(0);
        searchSourceBuilder.query(queryBuilder);
        //分组
        TermsAggregationBuilder aggregationCategoryId = AggregationBuilders.terms("group_categoryId").field(esField).size(1200000);
        searchSourceBuilder.aggregation(aggregationCategoryId);
        search.source(searchSourceBuilder);
        try{
            Set<Long> firstCategory = new HashSet<>();
            //搜索
            SearchResponse searchResponse = restHighLevelClient.search(search, RequestOptions.DEFAULT);
            Aggregations aggregations = searchResponse.getAggregations();
            if(aggregations != null){
                Terms brandTerms = aggregations.get("group_categoryId");
                List<? extends Terms.Bucket> brandBuckets = brandTerms.getBuckets();
                if(brandBuckets != null){
                    brandBuckets.forEach(bucket -> {
                        //将品类进行组装
                        String fullId = String.valueOf(bucket.getKey());
                        if(fullId.contains(Constants.SPLIT_STR_FULL_ID)){
                            String[] split = fullId.split(Constants.TRANSFER_STR + Constants.SPLIT_STR_FULL_ID);
                            firstCategory.add(Long.valueOf(split[0]));
                        }else{
                            firstCategory.add(Long.valueOf(fullId));
                        }
                    });
                }
            }
            if(!firstCategory.isEmpty()){
                Map<String, String> categoryMap = redisStringUtils.hGetAll(redisKey, Constants.REDIS_PRODUCT_INDEX);
                //遍历品类信息
                return firstCategory.stream().map(categoryId -> {
                    CategoryResponse categoryResponse = new CategoryResponse();
                    String category = categoryMap.get(String.valueOf(categoryId));
                    if(StringUtils.isNotEmpty(category)){
                        JSONObject jsonObject = JSONUtil.parseObj(category);
                        categoryResponse.setId(categoryId);
                        categoryResponse.setName(jsonObject.getStr("name"));
                        categoryResponse.setSort(jsonObject.getInt("sort"));
                    }
                    return categoryResponse;
                }).collect(Collectors.toList()).stream().sorted(Comparator.comparing(item -> item.getSort() == null ? 1 : item.getSort())).collect(Collectors.toList());
            }
            return null;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 查询二级分类
     * @param shopId            商城id
     * @param memberId          会员id
     * @param memberRoleId      会员角色id
     * @param categoryId        品类id
     */
    @Override
    public List<CategoryResponse> getSecondCategoryList(Long shopId, Long memberId, Long memberRoleId, Long categoryId){
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        //定义参数变量
        String esName;
        String esField;
        String redisKey;
        // 会员
        if(memberId != null && memberId > 0){
            queryBuilder.must(QueryBuilders.matchQuery("memberId", memberId));
            queryBuilder.must(QueryBuilders.matchQuery("memberRoleId", memberRoleId));
            esName = "customerCategory.fullId";
            esField = "customerCategory.fullId.keyword";
            redisKey = Constants.REDIS_KEY_CUSTOMER_CATEGORY;
        }else{
            esName = "customerCategory.category.fullId";
            esField = "customerCategory.category.fullId.keyword";
            redisKey = Constants.REDIS_KEY_CATEGORY;
        }

        // 拼接平台后台分类搜索
        if(categoryId != null && categoryId > 0){
            queryBuilder.must(QueryBuilders.prefixQuery(esName, String.format(Constants.CATEGORY_FULL_ID_NUM, categoryId)));
        }

        // 按商城环境
        if(shopId != null && shopId > 0){
            queryBuilder.must(QueryBuilders.matchQuery("commodityShopList.shopId", shopId));
        }

        //构建查询条件
        SearchRequest search = new SearchRequest(Constants.ES_COMMODITY_INDEX);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(0);
        searchSourceBuilder.query(queryBuilder);
        //分组
        TermsAggregationBuilder aggregationCategoryId = AggregationBuilders.terms("group_categoryId").field(esField).size(1200000);
        searchSourceBuilder.aggregation(aggregationCategoryId);
        search.source(searchSourceBuilder);
        try{
            Set<Long> secondCategory = new HashSet<>();
            //搜索
            SearchResponse searchResponse = restHighLevelClient.search(search, RequestOptions.DEFAULT);
            Aggregations aggregations = searchResponse.getAggregations();
            if(aggregations != null){
                Terms brandTerms = aggregations.get("group_categoryId");
                List<? extends Terms.Bucket> brandBuckets = brandTerms.getBuckets();
                if(brandBuckets != null){
                    brandBuckets.forEach(bucket -> {
                        //将品类进行组装
                        String fullId = String.valueOf(bucket.getKey());
                        if(fullId.contains(Constants.SPLIT_STR_FULL_ID)){
                            String[] split = fullId.split(Constants.TRANSFER_STR + Constants.SPLIT_STR_FULL_ID);
                            secondCategory.add(Long.valueOf(split[1]));
                        }
                    });
                }
            }
            if(!secondCategory.isEmpty()){
                Map<String, String> categoryMap = redisStringUtils.hGetAll(redisKey, Constants.REDIS_PRODUCT_INDEX);
                //遍历品类信息
                return secondCategory.stream().map(secondCategoryId -> {
                    String category = categoryMap.get(String.valueOf(secondCategoryId));
                    JSONObject jsonObject = JSONUtil.parseObj(category);
                    CategoryResponse categoryResponse = new CategoryResponse();
                    categoryResponse.setId(secondCategoryId);
                    categoryResponse.setName(jsonObject.getStr("name"));
                    return categoryResponse;
                }).collect(Collectors.toList());
            }
            return null;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 通过品类查询会员信息
     * @param shopId        商城id
     * @param categoryId    品类id
     */
    @Override
    public List<Long> getMemberIdByCategory(Long shopId, Long categoryId) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        // 拼接平台后台分类搜索
        if(categoryId != null && categoryId > 0){
            queryBuilder.must(QueryBuilders.prefixQuery("customerCategory.category.fullId", String.format(Constants.CATEGORY_FULL_ID_NUM, categoryId)));
        }

        // 按商城环境
        if(shopId != null && shopId > 0){
            queryBuilder.must(QueryBuilders.matchQuery("commodityShopList.shopId", shopId));
        }

        //构建查询条件
        SearchRequest search = new SearchRequest(Constants.ES_COMMODITY_INDEX);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(0);
        searchSourceBuilder.query(queryBuilder);
        //分组
        TermsAggregationBuilder aggregationMemberId = AggregationBuilders.terms("group_memberId").field("memberId").size(1200000);
        searchSourceBuilder.aggregation(aggregationMemberId);
        search.source(searchSourceBuilder);
        try{
            Set<Long> memberIdSet = new HashSet<>();
            //搜索
            SearchResponse searchResponse = restHighLevelClient.search(search, RequestOptions.DEFAULT);
            Aggregations aggregations = searchResponse.getAggregations();
            if(aggregations != null){
                Terms brandTerms = aggregations.get("group_memberId");
                List<? extends Terms.Bucket> brandBuckets = brandTerms.getBuckets();
                if(brandBuckets != null){
                    brandBuckets.forEach(bucket -> memberIdSet.add(Long.valueOf(String.valueOf(bucket.getKey()))));
                    return new ArrayList<>(memberIdSet);
                }
            }
            return null;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据店铺id集合查找最新上架的商品
     * @param storeIdListRequest 参数
     */
    @Override
    public Map<Long, List<CommoditySearchResponse>> getCommodityListByPublishTime(StoreIdListRequest storeIdListRequest) {
        List<Long> storeIdList = storeIdListRequest.getIdList();
        Integer count = storeIdListRequest.getCount();
        Long shopId = storeIdListRequest.getShopId();
        //查询商品
        List<Commodity> result = commodityRepository.findByStoreIdInAndCommodityShopListShopIdOrderByPublishTimeDesc(storeIdList, shopId);
        List<CommoditySearchResponse> commodityList = result.stream().map(commodity -> BeanUtil.copyProperties(commodity, CommoditySearchResponse.class)).collect(Collectors.toList());
        return getGroupCommodity(commodityList, count);
    }

    /**
     * 根据店铺id集合查找消息最高的商品
     * @param storeIdListRequest 参数
     */
    @Override
    public Map<Long, List<CommoditySearchResponse>> getCommodityListBySoldCount(StoreIdListRequest storeIdListRequest) {
        List<Long> storeIdList = storeIdListRequest.getIdList();
        Integer count = storeIdListRequest.getCount();
        Long shopId = storeIdListRequest.getShopId();
        //查询商品
        CommoditySearchRequest commoditySearchRequest = new CommoditySearchRequest();
        commoditySearchRequest.setStoreIdList(storeIdList);
        commoditySearchRequest.setShopId(shopId);
        commoditySearchRequest.setOrderType(SortTypeEnum.SoldDown.getCode());
        commoditySearchRequest.setCityCode(storeIdListRequest.getCityCode());
        commoditySearchRequest.setProvinceCode(storeIdListRequest.getProvinceCode());
        List<CommoditySearchResponse> commodityList = commodityService.queryCommodityList(commoditySearchRequest);
        return getGroupCommodity(commodityList, count);
    }

    /**
     * 通过店铺分组取count条数据
     * @param commodityList     商品列表
     * @param count             数量
     */
    private Map<Long, List<CommoditySearchResponse>> getGroupCommodity(List<CommoditySearchResponse> commodityList, Integer count){
        Map<Long, List<CommoditySearchResponse>> map = new HashMap<>();
        if(CollectionUtil.isNotEmpty(commodityList)){
            //遍历商品，根据店铺id分类
            commodityList.forEach(commoditySearchResponse -> {
                Long storeId = commoditySearchResponse.getStoreId();
                List<CommoditySearchResponse> commoditySearchResponseList = map.get(storeId);
                if(commoditySearchResponseList != null && !commoditySearchResponseList.isEmpty()){
                    //根据count，返回对应的商品条数
                    if(count != null && count > 0){
                        if(commoditySearchResponseList.size() < count){
                            commoditySearchResponseList.add(commoditySearchResponse);
                            map.put(storeId, commoditySearchResponseList);
                        }
                    }else{
                        //如果count为null，默认查询店铺下的全部商品
                        commoditySearchResponseList.add(commoditySearchResponse);
                        map.put(storeId, commoditySearchResponseList);
                    }
                }else{
                    commoditySearchResponseList = new ArrayList<>();
                    commoditySearchResponseList.add(commoditySearchResponse);
                    map.put(storeId, commoditySearchResponseList);
                }
            });
        }
        return map;
    }
}